Bouncing Babies Speed Patch by dOnut in 1997

This makes this old silly crap game playable on a modern computer.
Just start the game with "BBABIESP.COM" and everything will be fine.

The trick: a delay loop based on the vertical retrace is inserted.
Change the
   mov cx,01
above "waitscan:" to a bigger value to decrease speed.
Second trick: since inserting the delay loop at the start of the
program would delay the whole startup process, it is inserted
after the title screen has been drawn. The variable "dowait"
contains the data about if to wait (1) not (0).


For those interested the changed code:

Before                                        After
cs:38da  push bp                55            push ax              50
cs:38db  push si                56            mov ax,fffe          b8 fe ff
cs:38dc  push di                57            int 10               cd 10
cs:38dd  push ax                50            pop ax               58
cs:38de  push cx                51            pusha                60
cs:38df  push dx                52            call word ptr [0768] ff 16 68 07
cs:38e0  push bx                53            popa                 61
cs:38e1  call word ptr [0768]   ff 16 68 07   nop (x5)             90 90 90
cs:38e2  pop bx                 5b                                 90 90
cs:38e3  pop dx                 5a
cs:38e4  pop cx                 59
cs:38e5  pop ax                 58
cs:38e6  pop di                 5f
cs:38e7  pop si                 5e
cs:38e8  pop bp                 5d

Note that the delay is excuted in the interrupt routine...

----------------------------------------------------------------------------

Title patcher.asm
; by dOnut hOle

.286
.model tiny

.code
        org 100h
begin:  jmp init


; ****** MACROS ********
CR         equ     0Dh
LF         equ     0Ah
EOLN       equ     '$'
SIGNATURE  equ     0ffffh
SIGNATURE2 equ     0fffeh
INTERRUPT  equ     10h

;********* Resident Data **********
START             equ $
oldint_ofs        dw  0000h
oldint_seg        dw  0000h
int_no            db  INTERRUPT
dowait            db  0
data_start        db  01h                      ;Number of S&R-Loops
                  db  00h                      ;Flag: already Replaced ?
                  dw  0000                     ;offset to data_start2
                  db  02h                      ;search_seg1  (02=CS)
                  dw  38dah                    ;search_ofs1
                  dw  0000h                    ;search_seg_add1
                  db  07h                      ;search_bytes1
                  db  055h,056h,057h           ;search_data1
                  db  050h,051h,052h,053h  
                  db  01h                      ;replace_loops1
                  db  02h                      ;replace_seg1 (02=CS)
                  dw  38dah                    ;replace_ofs1
                  dw  0000h                    ;replace_seg_add1
                  db  18                       ;replace_bytes1
                  db  050h,0b8h,0feh,0ffh      ;replace_data1
                  db  0cdh,010h,058h,060h
                  db  0ffh,016h,068h,007h
                  db  061h,090h,090h,090h
                  db  090h,090h

save_sp           dw      0
                  db 100 DUP(0)
STACKFRAME        equ $

;***** a procedure of the interrupt-routine ******
set_address  proc near
          lodsb                     ; load segment from ds:si
          cmp al,00                 ; 00h=DS
          jz _DS_
          cmp al,01                 ; 01h=ES
          jz _ES_
          cmp al,02                 ; 02h=CS
          jz _CS_
          mov dx,ss                 ; >02h = SS
          jmp FOUR
_DS_:     mov dx,ss:[-02+bp]
          jmp FOUR
_ES_:      mov dx,ss:[-04+bp]
          jmp FOUR
_CS_:     mov dx,ss:[14h+bp]
FOUR:     lodsw                    ; load segment_ofs from ds:si
          mov di,ax                ; and store it into di
          lodsw                    ; load segment_add from ds:si 
          add ax,dx                ; add it to segment in dx
          mov es,ax                ; es:di = (seg+seg_add):seg_ofs
          ret
endp set_address

;******* this is the interrupt-routine *********
new_int   proc far
          pushf
          pusha

          cmp ax,SIGNATURE         ; asking for signature ???
          jne normal

givesig:  popa
          popf
          mov bx,SIGNATURE         ; signature FFFF in bx given back
          iret

normal:   cmp ax,SIGNATURE2        ; called from replacement
          jne normal2

          cmp cs:[dowait],1
          jne wait_end
          mov cx,01
waitscan: mov dx,03dah
wait1:    in al,dx
          test al,08h
          jz wait1
wait2:    in al,dx
          test al,08h
          jnz wait2
          loop waitscan
wait_end: popa
          popf
          iret

normal2:  mov bp,sp
          push ds
          push es
          cld
          push cs
          pop ds

          cmp ax,0245h
          jne normal3
          mov dowait,1

normal3:  mov si,offset data_start
          lodsb                     ; load s&R-loops from ds:si
          cbw
          xchg ax,cx                ; set outer loop-counter
search:       push cx
              mov bx,si
              lodsb                 ; load replaced-flag from ds:si
              or al,al              ; flag = 0 ?
              lodsw                 ; load offset to next data from ds:si
              push ax
              jnz endloop           ; if flag <> 0 then jump over this loop
              call set_address      ; set address to search
              lodsb                 ; load search_bytes from ds:si
              cbw
              xchg ax,cx            ; and store it into inner loop-counter
              repz cmpsb            ; compare with search_data
              jnz endloop           ; not equal (string not found)
              lodsb                 ; load replace-loops from ds:si
              cbw
              xchg ax,cx            ; and store it into middle loop counter
Loop_me:          push cx
                  call set_address  ; set address to replace
                  lodsb             ; load replace_bytes from ds:si
                  cbw
                  xchg ax,cx        ; and store it into inner loop counter
                  repz movsb        ; replace bytes
                  ;mov byte ptr [bx],01  ; set flag to 'replaced'
                  pop cx
              loop loop_me  
endloop:      pop si                ; offset to next data
              pop cx
          loop search
endsearch:pop es
          pop ds
jumpold:  popa
          popf
          jmp dword ptr cs:[oldint_ofs]
new_int endp


;********* not resident data ************
FINISH      equ     $
MESS        db      'Bouncing Babies speed patch by dOnut hOle 1997',CR,LF,EOLN
PROG        db      'BBabies.exe',0
FNAME       db      60 dup(0)
PARAM       dw      0
            db      80h,0
PARAM1      dw      5 dup(0)
ERR1        db      'ERROR: Not enough memory.  '
ERR2        db      'Starting as TSR.',CR,LF,EOLN
REMOVE      db      'Removing TSR. ',CR,LF,EOLN

;******* the main program is starting here ************
init:
            cli
            mov [save_sp],sp
            mov sp,offset STACKFRAME    ; define stack
            sti

            mov ax,SIGNATURE
            xor bx,bx
            int INTERRUPT               ; check if already installed
            cmp bx,SIGNATURE
            jne install                 ; interrupt not yet hooked

            ;******* Uninstall TSR ********
            mov al,[int_no]
            mov ah,35h
            int 21h                     ; get segment of interrupt (es)
            push ds
            lds dx,dword ptr es:[oldint_ofs]
            mov ah,25h
            int 21h                     ; restore interrupt-vector
            pop ds

            push es
            mov es,es:[02ch]            ; get segment from PSP
            mov ah,49h
            int 21h                     ; free Memory
            pop es
            mov ah,49h
            int 21h                     ; free Memory

            push cs
            pop ds
            mov ah,9h
            mov dx,offset REMOVE
            int 21h                     ; print message
            jmp exit

install:    ;********* install interrupt **********
            mov ah,35h
            mov al,cs:[int_no]
            int 21h                     ; read interrupt vector
            mov cs:[oldint_ofs],bx      ; store offset 
            mov cs:[oldint_seg],es      ; store segment 
            mov ah,25h  
            mov dx,offset new_int
            int 21h                     ; set new interrupt vector

            mov ah,9h
            mov dx,offset MESS
            int 21h                     ; print message

            push cs
            pop es
            mov bx,offset ENDCODE       ;Get end of memory
            add bx,15
            mov cl,4                
            shr bx,cl                   ;div 16
            mov ah,4Ah            
            int 21h                     ;Reallocate memory
            jnc GetName                 ;If no error, continue

            mov ah,9h
            mov dx,offset ERR1
            int 21h                     ;Write error-string
            jmp tsr

GetName:    ;****** get the path from the environment ****
            mov es,cs:[02ch]            ;Segment of Environment
            xor di,di
            xor ax,ax
SearchEnv:    cmp al,es:[di]            ;Search two zeroes
              je SearchEnd
              mov cx,0ffffh
              repnz scasb
            jmp SearchEnv
SearchEnd:  add di,03                   ;es:di points at path+name
            push di
            mov cx,100h                 ;Search End of string 
            repnz scasb
            not cl                      ;Cl contains length
            std
            mov al,'\'
            repnz scasb                 ;search last '\'
            add cl,3
            cld
            ;******* assemble full name from path and given name ********
            pop di
            mov si,di
            mov di,offset FNAME
            push es
            pop ds
            push cs
            pop es
            rep movsb                   ; path is copied to NAME
            push cs
            pop ds
            mov si,offset PROG
COPY_PROG:  cmp byte ptr [si],00
            je COPY_END
            MOVSB                       ; PROG is copied to NAME
            jmp COPY_PROG               
COPY_END:   MOVSB
            ;****** load and execute the child program **********
            mov ax,cs
            mov PARAM,ax
            mov PARAM1,ax
            mov bx,offset PARAM
            mov dx,offset FNAME
            mov ah,4Bh
            mov al,00h
            int 21h                     ;Load and execute child program
            jnc uninstall               ;If no error, continue

            mov ah,9h                   
            mov dx,offset ERR2
            int 21h                     ;Write error- string
            jmp tsr

uninstall:  ;********** restore old interrupt ***********
            mov ah,25h                  ;Restore interrupt vector
            mov al,[int_no]
            mov dx,[oldint_ofs]
            mov bx,[oldint_seg]
            mov ds,bx
            int 21h

EXIT:       push cs
            pop ds
            cli
            mov sp,[save_sp]
            sti
            mov ax,4C00h                     ;Exit with error code 0
            int 21h

TSR:        ;********** go resident ***********
            mov dx,offset FINISH             ;Offset of booster
            add dx,15
            mov cl,4
            shr dx,cl
            mov ax,3100h
            int 21h                          ;Exit with ejection of booster
                                         
ENDCODE     equ $
end      begin
